package com.hq.common.utils;

import com.hq.common.utils.cipher.MD5;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public class PropertiesCryptConvert {
    private static final Logger logger = LoggerFactory.getLogger(PropertiesCryptConvert.class);
    private static String OS_LINE_SEPARATOR = System.getProperty("line.separator");
    private static final String KEY_MD5_NAME = "MD5";
    private String propertiesPath;
    private static final String PROPERTIES_LINE_EQUAL_SPLIT = "=";
    //private static final String PROPERTIES_LINE_COLON_SPLIT = ":";
    private static final String ENCRPYT_KEY_BUNCH = "abcdefghigklmn123456opqrstuvwxyz";
    private static final String ENCRPYT_PREFIX = "{SGCC}";
    private static final String[] KEYWORD_ENCRYPTED = new String[]{"password", "username", "url"};

    public PropertiesCryptConvert(String propertiesPath) {
        this.propertiesPath = propertiesPath;
    }

    private static boolean isKeyword(String keyName) {
        if (keyName == null || keyName.length() == 0) {
            return false;
        }
        for (String keyword : KEYWORD_ENCRYPTED) {
            if (keyName.toLowerCase().contains(keyword)) {
                return true;
            }
        }
        return false;
    }

    public Properties getProperties(boolean coverSource) {
        Properties result = new Properties();
        List<String> lineList = new ArrayList<String>();
        BufferedReader bufReader = null;
        try {
            bufReader = new BufferedReader(new InputStreamReader(new FileInputStream(propertiesPath), "GBK"));
            String line, key, value;
            while ((line = bufReader.readLine()) != null) {
                line = line.trim();
                if (line.length() > 0) {
                    if (line.startsWith("#")) { //处理注释行
                        lineList.add(line);
                        lineList.add(OS_LINE_SEPARATOR);
                        continue;
                    } else if (line.startsWith(KEY_MD5_NAME + "=")) { //处理MD5行
                        continue;
                    }
                    String[] lineValue = line.split(PROPERTIES_LINE_EQUAL_SPLIT, 2);
                    if (lineValue.length == 2) {
                        key = lineValue[0].trim();
                        value = lineValue[1].trim();
                        if (isKeyword(key) && !isEncrpyted(value)) {
                            lineList.add(key + PROPERTIES_LINE_EQUAL_SPLIT + getEncrpytedValue(value));
                        } else {
                            lineList.add(line);
                        }
                        lineList.add(OS_LINE_SEPARATOR);
                        value = getDecryptedValue(value);
                        result.setProperty(key, value);
                    } else {
                        logger.warn("Properties配置有误!  Line:{}", line);
                    }
                } else {
                    lineList.add(OS_LINE_SEPARATOR);
                }
            }
        } catch (FileNotFoundException e) {
            logger.error("Properties配置文件未找到：{}", propertiesPath);
        } catch (IOException e) {
            logger.error("保存Properties配置文件失败：{}", propertiesPath);
        } finally {
            if (bufReader != null) {
                try {
                    bufReader.close();
                } catch (IOException e) {
                    logger.error("关闭配置文件流异常!");
                }
            }
        }
        if (coverSource && !this.verifyFileMd5()) {
            String md5Str = this.getMd5ByString(lineList);
            lineList.add(0, KEY_MD5_NAME + "=" + md5Str);
            lineList.add(1, OS_LINE_SEPARATOR);
            BufferedWriter bufWriter = null;
            try {
                bufWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(propertiesPath, false), "GBK"));
                for (String lineStr : lineList) {
                    bufWriter.write(lineStr);
                }
                bufWriter.flush();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (bufWriter != null) {
                    try {
                        bufWriter.close();
                    } catch (IOException e) {
                        logger.error("文件写入失败!");
                    }
                }
            }
        }
        return result;
    }

    private String getMd5ByString(List<String> lineList) {
        StringBuilder stringBuilder = new StringBuilder();
        for (String strLine : lineList) {
            stringBuilder.append(strLine);
        }
        return MD5.md5DigestAsHex(stringBuilder.toString()).toUpperCase();
    }

    private boolean verifyFileMd5() {
        BufferedReader bufReader = null;
        try {
            bufReader = new BufferedReader(new InputStreamReader(new FileInputStream(propertiesPath), "GBK"));
            String line = bufReader.readLine();
            if (line != null) {
                if (line.startsWith(KEY_MD5_NAME)) {
                    String[] lineValue = line.split(PROPERTIES_LINE_EQUAL_SPLIT, 2);
                    if (lineValue.length == 2) {
                        String md5Str = lineValue[1];
                        StringBuilder stringBuilder = new StringBuilder();
                        while ((line = bufReader.readLine()) != null) {
                            //line = line.equals("") ? OS_LINE_SEPARATOR : line;
                            stringBuilder.append(line).append(OS_LINE_SEPARATOR);
                        }
                        String newMd5 = MD5.md5DigestAsHex(stringBuilder.toString()).toUpperCase();
                        return md5Str.equals(newMd5);
                    }
                }
            }
        } catch (Exception ex) {
            logger.error("计算文件MD5异常!");
        } finally {
            try {
                if (bufReader != null) {
                    bufReader.close();
                }
            } catch (IOException e) {
                logger.error("关闭文件流失败!");
            }
        }
        return false;
    }

    private static boolean isEncrpyted(String value) {
        return value.startsWith(ENCRPYT_PREFIX);
    }

    public static String getDecryptedValue(String value) {
        if (value != null && value.length() > 0) {
            if (isEncrpyted(value)) {//已经加密过
                try {
                    value = EncrpytUtils.decryptDES(value.replace(ENCRPYT_PREFIX, ""), ENCRPYT_KEY_BUNCH);
                } catch (Exception e) {
                    logger.error("解密失败!", e);
                }
            }
        }
        return value;
    }

    public static String getEncrpytedValue(String value) {
        String result = value;
        if (value != null && value.length() > 0) {
            try {
                result = EncrpytUtils.encryptDES(value, ENCRPYT_KEY_BUNCH);
                result = ENCRPYT_PREFIX + result;
                result = result.replaceAll(OS_LINE_SEPARATOR, "");
            } catch (Exception e) {
                logger.error("加密失败!", e);
            }
        }
        return result;
    }

}
